package com.ponhu.ea2.goodsCenter.bms.api.support;

import com.alibaba.fastjson.JSON;
import com.ponhu.ea2.common.basic.exception.enums.GlobalExceptionEnums;
import com.ponhu.ea2.common.basic.model.ResponseBean;
import com.ponhu.ea2.goodsCenter.bms.api.utils.CommonUtils;
import com.ponhu.ea2.properties.GoodsProperties;
import com.ponhu.ea2.support.exception.BusinessRuntimeException;
import io.netty.util.concurrent.FastThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.ponhu.ea2.enums.ResponseCodeEnum.NOT_ERROR_CODE;
import static com.ponhu.ea2.enums.ResponseCodeEnum.PARAMETER_IS_INCORRECT_800001;

@Slf4j
@Aspect
@Component
public class LogAop {

    @Autowired
    private FastThreadLocal<String> traceIdLocal;

    @Resource
    GoodsProperties goodsProperties;

    @Pointcut("execution(* com.ponhu.ea2.goodsCenter.bms.api.controller.*.*(..))")
    private void annotationAspect() {

    }

    @Around("annotationAspect()")
    public Object doAroundService(ProceedingJoinPoint proceedingJoinPoint) {
        String traceId = CommonUtils.getTraceId();
        traceIdLocal.set(traceId);

        String servletPath = null;
        try {
            ServletRequestAttributes servletRequestAttributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            servletPath = servletRequestAttributes.getRequest().getServletPath();
        } catch (Exception e) {
            //nothing to do
        }
        try {
            List<Object> args = Arrays.stream(proceedingJoinPoint.getArgs())
                    .filter(arg -> !(arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile))
                    .collect(Collectors.toList());
            log.info("{} ===>> [{}] ===>> 入参={}", servletPath, traceId, JSON.toJSONString(args));

            Object proceed = proceedingJoinPoint.proceed();
            String logInfo = JSON.toJSONString(proceed);
            // 现在服务端追查日志不方便,增加出参信息

            // 剔除列表页日志信息
            if (BooleanUtils.isTrue(goodsProperties.getEnableBmsLogPrintStatus())) {
                if (StringUtils.isNotBlank(logInfo) && !logInfo.contains("pageCount") && !goodsProperties.getUnableLogUrl().contains(servletPath)) {
                    log.info("{} ===>> [{}] ===>> 出参={}", servletPath, traceId, logInfo);
                } else {
                    log.info("{} ===>> [{}] ===>> 请求成功", servletPath, traceId);
                }
            } else {
                log.info("{} ===>> [{}] ===>> 日志输出已关闭，请求成功", servletPath, traceId);
            }
            return proceed;
        } catch (Throwable throwable) {
            if (throwable instanceof BusinessRuntimeException) {
                BusinessRuntimeException ex = (BusinessRuntimeException) throwable;
                log.error("{} ===>> [{}] ===>> 业务异常：[code={}, msg={}]", servletPath, traceId,
                        ex.getCodeEnum() == null ? "未定义异常编码" : ex.getCodeEnum().getCode(), ex.getCodeEnum() == null ? ex.getLocalizedMessage() : ex.getCodeEnum().getMsg());
                return ResponseBean.error(ex.getCodeEnum() == null ? NOT_ERROR_CODE.getCode() : ex.getCodeEnum().getCode(), ex.getCodeEnum() == null ? ex.getLocalizedMessage() : ex.getCodeEnum().getMsg());
            }

            //校验框架异常处理
            if (throwable instanceof ConstraintViolationException) {
                ConstraintViolationException exs = (ConstraintViolationException) throwable;

                Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
                String msg = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));
                log.error("{} ===>> [{}] ===>> 参数校验异常：[msg={}]", servletPath, traceId, msg);
                return ResponseBean.error(PARAMETER_IS_INCORRECT_800001.getCode(), msg);
            }
            throwable.printStackTrace();
            log.error("{} ===>> [{}] ===>> 系统异常={}", servletPath, traceId, throwable.getMessage());
            log.error("系统异常:", throwable);
            return ResponseBean.error("服务器开小差了,o(╥﹏╥)o - " + GlobalExceptionEnums.EXCEPTION_GOODS.getCustomExceptionName());
        } finally {
            traceIdLocal.remove();
        }
    }


}
